package com.atldy.commerce.config;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executor;

/**
 * @version 1.0
 * @Author: lidongyang
 * @CreateTime: 2021-08-05 23:20
 * @Description： 通过nacos下放动态路由配置，监听nacos中路由配置变更
 */
@Component
@Slf4j
@DependsOn({"gatewayConfig"})
public class DymincRouteByNacosConfigImpl {


    /**
     * nacos 配置服务
     */
    private ConfigService configService;

    private final DynamicRouteServiceImpl dynamicRouteService;

    public DymincRouteByNacosConfigImpl(DynamicRouteServiceImpl dynamicRouteService) {
        this.dynamicRouteService = dynamicRouteService;
    }

    /**
     * 初始化nacos config 配置
     */
    private ConfigService initConfigService() {
        log.info(" load start init nacos config ");
        try {
            Properties properties = new Properties();
            properties.setProperty("serverAddr", GatewayConfig.NACOS_SERVER_ADDR);
            properties.setProperty("namespace", GatewayConfig.NACOS_NAMESPACE);
            ConfigService configService = NacosFactory.createConfigService(properties);
            return configService;
        } catch (Exception exception) {
            log.error("config service init error：【{}】", exception.getMessage(), exception);
            return null;
        }
    }

    /**
     * 初始化从nacos config 拉取路由配置
     */
    @PostConstruct
    private void initializeRoute() {
        log.info("init gateway route");
        try {
            // TODO: 2021/8/6 获取nacos config 配置
            configService = initConfigService();
            if (configService == null) {
                log.error("initConfigService init error");
                return;
            }
            //根据  dataId,  group,  timeoutMs 从 naco config获取路由定义信息
            String configInfo = configService.getConfig(GatewayConfig.NACOS_ROUTE_DATA_ID, GatewayConfig.NACOS_ROUTE_GROUP, GatewayConfig.DEFAULT_TIMEOUT);
            log.warn("load gateway init nacos coonfig {}", JSONUtil.formatJsonStr(configInfo));
            List<RouteDefinition> routeDefinitions = JSON.parseArray(configInfo, RouteDefinition.class);
            if (CollectionUtil.isNotEmpty(routeDefinitions)) {
                routeDefinitions.stream().forEach(routeDefinition -> {
                    dynamicRouteService.addRouteDefinition(routeDefinition);
                });
            }
        } catch (NacosException e) {
            log.error("init gateway error", e.getMessage(), e);
        }
        //初始化配置监听
        dynamicNacosConfigListener(GatewayConfig.NACOS_ROUTE_DATA_ID, GatewayConfig.NACOS_ROUTE_GROUP);
    }


    /**
     * 监听nacos 下发路由配置
     */
    private void dynamicNacosConfigListener(String dataId, String group) {
        try {
            configService.addListener(dataId, group,
                    //匿名内部类，nacos config 客户端添加监听器
                    new Listener() {
                        /**自定义线程池*/
                        @Override
                        public Executor getExecutor() {
                            return null;
                        }

                        /**监听器收到配置更新 nacos config 最新的配置定义*/
                        @Override
                        public void receiveConfigInfo(String s) {
                            log.info("load nacos  config start  update " + JSONUtil.formatJsonStr(s));
                            List<RouteDefinition> routeDefinitions = JSON.parseArray(s, RouteDefinition.class);
                            String updateRoutes = dynamicRouteService.updateRoutes(routeDefinitions);
                            log.info("load nacos  config end  update result:  " + updateRoutes);
                        }
                    });
        } catch (NacosException e) {
            log.error("nacos config update error :[{}]" + e.getMessage(), e);
        }
    }

}